﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
using System.Messaging;
using System.Security.Principal;

namespace PSE.Deployment.Util
{
    public class MSMQ
    {
        public static bool CheckInstalled()
        {
            return WindowsRegistry.KeyExists(@"SYSTEM\CurrentControlSet\Services\MSMQ", Registry.LocalMachine);
        }

        /// <summary>
        /// Verifica a existência de um fila em um servidor
        /// </summary>
        /// <param name="serverName">Nome do servidor</param>
        /// <param name="queueName">Nome completo da fila, no caso de filas privadas o nome deve seguir o formato private$\nomeFila</param>
        /// <returns></returns>
        public static bool QueueExists(string serverName, string queueName)
        {
            if (string.IsNullOrEmpty(serverName))
                throw new ArgumentNullException("serverName");

            if (string.IsNullOrEmpty(queueName))
                throw new ArgumentNullException("queueName");

            bool queueExists = false;

            try
            {
                //procurar nas filas privadas
                MessageQueue[] privateQueues = MessageQueue.GetPrivateQueuesByMachine(serverName);
                if (privateQueues != null && privateQueues.Length > 0)
                {
                    if (privateQueues.Count<MessageQueue>(x => x.QueueName.ToLower() == queueName.ToLower()) > 0) //.Contains<MessageQueue>(x => x.QueueName == queueName))
                        queueExists = true;
                }

                //se n encontrou nas filas privadas
                if (!queueExists)
                {
                    //procurar nas filas publicas
                    MessageQueue[] publicQueues = MessageQueue.GetPublicQueuesByMachine(serverName);
                    if (publicQueues != null && publicQueues.Length > 0)
                    {
                        if (publicQueues.Count<MessageQueue>(x => x.QueueName.ToLower() == queueName.ToLower()) > 0)
                            queueExists = true;
                    }
                }
            }
            catch
            {
                queueExists = false;
            }

            return queueExists;

        }
        public static bool CheckAccess()
        {
            bool hasAccess = false;
            MessageQueue mq = null;
            try
            {
                string msmqQueuePath = @".\Private$\QueueCheckAccess";

                if (!MessageQueue.Exists(msmqQueuePath))
                {
                    mq = MessageQueue.Create(msmqQueuePath);
                    if (mq != null)
                        hasAccess = true;

                    MessageQueue.Delete(msmqQueuePath);
                }
                else
                {
                    MessageQueue.Delete(msmqQueuePath);
                    mq = MessageQueue.Create(msmqQueuePath);
                    if (mq != null)
                        hasAccess = true;

                    MessageQueue.Delete(msmqQueuePath);

                }
            }
            catch
            {
                hasAccess = false;
            }
            finally
            {
                if (mq != null)
                {
                    mq.Close();
                    mq.Dispose();
                }
            }

            return hasAccess;
        }

        public static void Create(string queueName)
        {
            if (!MessageQueue.Exists(queueName))
            {
                MessageQueue mq = MessageQueue.Create(queueName);

                Trustee tr = new Trustee(GetLocalSystemSid());
                MessageQueueAccessControlEntry entry = new MessageQueueAccessControlEntry(tr, MessageQueueAccessRights.FullControl, AccessControlEntryType.Allow);
                mq.SetPermissions(entry);
                mq.Close();
                mq.Dispose();
            }
        }

        private static string GetLocalSystemSid()
        {
            SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
            return ((NTAccount)sid.Translate(typeof(NTAccount))).Value;
        }
        
        public static void Delete(string queueName)
        {
            if (MessageQueue.Exists(queueName))
            {
                MessageQueue.Delete(queueName);
            }
        }
    }

}
